package com.bot.nft.module.op.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bot.common.exception.CommonException;
import com.bot.nft.core.enums.op.AirdropEnum;
import com.bot.nft.module.op.domain.OpAirExeLog;
import com.bot.nft.module.op.domain.OpAirHoldLimit;
import com.bot.nft.module.op.domain.OpAirInfo;
import com.bot.nft.module.op.domain.OpAirList;
import com.bot.nft.module.op.domain.bo.OpAirListBo;
import com.bot.nft.module.op.domain.bo.OpAirMbHoldBo;
import com.bot.nft.module.op.domain.vo.OpAirListVo;
import com.bot.nft.module.op.mapper.*;
import com.bot.nft.module.op.service.IOpAirListService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 空投活动服务实现类
 * </p>
 *
 * @author zhangkaige
 * @since 2024-01-24
 */
@Service
public class OpAirListServiceImpl implements IOpAirListService {

    //空投活动白名单Mapper
    @Resource
    private OpAirListMapper opAirListMapper;

    //空投活动Mapper
    @Resource
    private OpAirInfoMapper opAirInfoMapper;

    //空投活动持有条件Mapper
    @Resource
    private OpAirHoldLimitMapper holdMapper;

    //执行日志Mapper
    @Resource
    private OpAirExeLogMapper exeLogMapper;

    @Override
    public Page<OpAirListVo> getAirListPage(Integer pageNo, Integer pageSize, String airId, String phone) {
        //分页信息
        Page<OpAirListVo> page = new Page<>(pageNo, pageSize);
        //查询白名单
        opAirListMapper.airListVoPage(page, airId, phone);

        return page;
    }

    @Override
    public Boolean gneAirList(String airId) {
        OpAirInfo airInfoVo = opAirInfoMapper.selectById(airId);
        //判断是否到快照时间
        Date nowTime = new Date();
        //判断空投活动条件类型
        if (airInfoVo.getConType().equals(AirdropEnum.LIST_CONDITION.getValue())) {
            throw new CommonException("特殊投递任务无需快照");
        }
        //判断快照时间是否到达
        if (nowTime.before(airInfoVo.getSnaTime())) {
            throw new CommonException("未到快照执行时间");
        }
        //判断活动状态
        if (airInfoVo.getStatus().equals(AirdropEnum.DISABLE_STATUS.getValue())) {
            throw new CommonException("活动未启用");
        }
        if (airInfoVo.getStatus().equals(AirdropEnum.SNAPSHOT_STATUS.getValue())) {
            throw new CommonException("活动已快照");
        }
        if (airInfoVo.getStatus().equals(AirdropEnum.EXECUTED_STATUS.getValue())) {
            throw new CommonException("活动已执行");
        }
        //1.查询空投活动持有限制条件
        QueryWrapper<OpAirHoldLimit> holdWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<OpAirHoldLimit> holdLambda = holdWrapper.lambda().eq(OpAirHoldLimit::getAirId, airId);
        List<OpAirHoldLimit> opAirHoldLimits = holdMapper.selectList(holdLambda);
        //2.把条件放入放入Mapper集合
        Map<String, Integer> conditionMap = new HashMap<>();
        for (OpAirHoldLimit holdLimit : opAirHoldLimits) {
            conditionMap.put(holdLimit.getNftId(), holdLimit.getHoldNum());
        }
        //2.查询用户持有指定藏品藏品的信息
        QueryWrapper<OpAirMbHoldBo> mbHoldWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<OpAirMbHoldBo> mbHoldLambda = mbHoldWrapper.lambda().in(OpAirMbHoldBo::getMbId,
                conditionMap.keySet());
        List<OpAirMbHoldBo> opAirMbHoldBos = opAirListMapper.selectMbHoldList(conditionMap.keySet(),
                airInfoVo.getSnaTime());

        //3.把用户持有藏品数量的放入Mapper中
        Map<String, List<Integer>> mbHoldMap = new HashMap<>();
        for (OpAirMbHoldBo mbHoldBo : opAirMbHoldBos) {
            String mbId = mbHoldBo.getMbId();
            if (mbHoldMap.get(mbId) == null) {
                //持有份数的集合
                List<Integer> countList = new ArrayList<>();
                //用户持有Mapper
                mbHoldMap.put(mbId, countList);
            }
            List<Integer> countList = mbHoldMap.get(mbId);
            //计算份数
            Integer num = mbHoldBo.getHoldNum() / conditionMap.get(mbHoldBo.getNftId());
            countList.add(num);

        }
        //4.生成空投白名单
        List<OpAirList> airListList = new ArrayList<>();
        Set<String> mbIdList = mbHoldMap.keySet();
        int limitNum = opAirHoldLimits.size();
        //空投份数
        int airCount = 0;
        for (String mbId : mbIdList) {
            List<Integer> holdList = mbHoldMap.get(mbId);
            if (holdList.size() == limitNum) {
                Integer minCount = Collections.min(holdList);
                if (minCount > 0) {
                    OpAirList airList = new OpAirList();
                    airListList.add(airList);
                    airList.setAirId(airId);
                    airList.setMbId(mbId);
                    airList.setStatus(AirdropEnum.NO_DELIVERY_STATUS.getValue());
                    airList.setCount(minCount);
                    airCount = airCount + minCount;
                }
            }
        }
        //空投执行日志
        OpAirExeLog airExeLog = new OpAirExeLog();
        airExeLog.setExeTime(new Date());
        airExeLog.setStatus(AirdropEnum.EXECUTION_SUCCESSFUL.getValue());
        airExeLog.setAirId(airId);
        airExeLog.setTaskType(AirdropEnum.SNAPSHOT_TASK.getValue());
        airExeLog.setRemark("快照成功，预计空投" + airCount + "份");
        //添加执行日志
        exeLogMapper.insert(airExeLog);
        if (airListList.size() == 0) {
            throw new CommonException("没有会员符合空投条件");
        }
        //5.保存空投白名单
        boolean flag = opAirListMapper.insertBatch(airListList);
        //修改活动状态
        UpdateWrapper<OpAirInfo> airInfoWrapper = new UpdateWrapper<>();
        LambdaUpdateWrapper<OpAirInfo> lambda =
                airInfoWrapper.lambda().eq(OpAirInfo::getId, airId).set(OpAirInfo::getStatus,
                        AirdropEnum.SNAPSHOT_STATUS.getValue());
        int update = opAirInfoMapper.update(null, lambda);
        return flag && update > 0;
    }

    @Override
    public Boolean addAirList(OpAirListBo opAirListBo) {
        OpAirList airList = BeanUtil.copyProperties(opAirListBo, OpAirList.class);
        int insert = opAirListMapper.insert(airList);
        return insert > 0;
    }

    @Override
    public Boolean delAirListById(String id) {
        int count = opAirListMapper.deleteById(id);
        return count > 0;
    }

    @Override
    public List<OpAirList> getAirList(String airId) {
        //查询条件
        LambdaQueryWrapper<OpAirList> airListWrapper = new LambdaQueryWrapper<>();
        airListWrapper.eq(OpAirList::getAirId, airId)
                .eq(OpAirList::getStatus, AirdropEnum.NO_DELIVERY_STATUS.getValue());

        return opAirListMapper.selectList(airListWrapper);
    }
}
